#include "DataCenter.h"
#include "StdSqlite3.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <openssl/sha.h>
#define DBPath "./chatroom.db"

static SQL *s; // 定义一个静态全局变量（避免多次在不同函数中打开关闭数据库）

bool DataCenterInit()
{
    s = StdSqlite3Init(DBPath);
    if (s == NULL)
    {
        return false;
    }
    char sql[] = "create table if not exists user(name text primary key,passwd text not null,salt text not null);";                             // 用户列表
    char sql2[] = "create table if not exists friend(fromname text, toname text, isok integer);";                                               // 好友列表  isok 0未读 1已读同意 2已读不同意
    char sql3[] = "create table if not exists chathistory(fromname text, toname text, time DATETIME DEFAULT CURRENT_TIMESTAMP, content text);"; // 聊天记录表
    char sql4[] = "create table if not exists groupchat(groupleader text, groupname text not null, member text);";                              // 群聊表
    return SQLExec(s, sql) && SQLExec(s, sql2) && SQLExec(s, sql3) && SQLExec(s, sql4);
}

bool IsUserExist(const char *name)
{
    char sql[1024] = {0};
    sprintf(sql, "select count(*) from user where name = '%s';", name);
    char **result = GetTableInfo(s, sql, NULL, NULL);
    if (result == NULL)
        return false;
    int count = atoi(result[1]);
    FreeTableInfo(result);
    return count != 0;
}

bool IsFriendExist(const char *fromname, const char *toname)
{
    char sql[1024] = {0};
    sprintf(sql, "select count(*) from friend where (fromname = '%s' and toname = '%s') and (isok = 1);", fromname, toname);
    char **result = GetTableInfo(s, sql, NULL, NULL);
    if (result == NULL)
        return false;
    int count = atoi(result[1]);
    FreeTableInfo(result);
    return count != 0;
}

// 生成随机盐
char *GenerateSlat()
{
    srand(time(NULL));
    char salt[16] = {0};
    for (int i = 0; i < 17; i++)
    {
        salt[i] = 32 + rand() % 95;
    }
    return strdup(salt);
}

// 生成哈希值
char *HashPasswd(const char *passwd, const char *salt)
{
    int newLen = strlen(passwd) + strlen(salt) + 1;
    char *newPasswd = (char *)malloc(newLen);
    if (newPasswd == NULL)
    {
        printf("AddNewUser malloc error\n");
        return false;
    }
    memset(newPasswd, 0, newLen);
    strcat(newPasswd, passwd);
    strcat(newPasswd, salt);

    unsigned char hashPasswd[SHA256_DIGEST_LENGTH] = {0};
    SHA256(newPasswd, strlen(newPasswd), hashPasswd);

    char result[SHA256_DIGEST_LENGTH * 2] = {0};
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
    {
        char temp[8] = {0};
        sprintf(temp, "%x", hashPasswd[i]);
        strcat(result, temp);
    }
    free(newPasswd);
    return strdup(result);
}

bool AddNewUser(const char *name, const char *passwd)
{
    char *salt = GenerateSlat();
    char *result = HashPasswd(passwd, salt);
    char sql[1024] = {0};
    sprintf(sql, "insert into user values('%s','%s', '%s');", name, result, salt);
    free(salt);
    free(result);
    return SQLExec(s, sql);
}

// 获取用户的盐
char *GetUserSalt(const char *name)
{
    char sql[1024] = {0};
    sprintf(sql, "select salt from user where name = '%s';", name);
    char **result = GetTableInfo(s, sql, NULL, NULL);
    if (result == NULL)
    {
        return NULL;
    }
    char *salt = strdup(result[1]); // result[0]为列名
    FreeTableInfo(result);
    return salt;
}

bool IsAccountEqual(const char *name, const char *passwd)
{
    char sql[1024] = {0};
    char *salt = GetUserSalt(name);
    if (salt == NULL)
    {
        return NULL;
    }
    char *hashpasswd = HashPasswd(passwd, salt);
    sprintf(sql, "select count(*) from user where name = '%s' and passwd = '%s';", name, hashpasswd);
    free(hashpasswd);
    free(salt);
    char **result = GetTableInfo(s, sql, NULL, NULL);
    if (result == NULL)
        return false;
    int count = atoi(result[1]);
    FreeTableInfo(result);
    return count != 0;
}

bool AddNewFriend(const char *fromename, const char *toname)
{
    char sql[1024] = {0};
    sprintf(sql, "insert into friend values('%s','%s',%d);", fromename, toname, 0);
    return SQLExec(s, sql);
}

bool DelFriend(const char *fromname, const char *toname)
{
    char sql[1024] = {0};
    sprintf(sql, "delete from friend where (fromname = '%s' and toname = '%s') or (fromname = '%s' and toname = '%s');", fromname, toname, toname, fromname);
    return SQLExec(s, sql);
}

bool AddChatHistory(const char *fromname, const char *toname, const char *content)
{
    char sql[1024] = {0};
    sprintf(sql, "insert into chathistory (fromname, toname, content) values('%s','%s','%s');", fromname, toname, content);
    return SQLExec(s, sql);
}

char *GetChatHiostory(const char *fromname, const char *toname)
{
    char sql[1024] = {0};
    int row = 0;
    int colnm = 0;
    sprintf(sql, "SELECT fromname, time, content FROM chathistory where (fromname = '%s' and toname = '%s') or (fromname = '%s' and toname = '%s') ORDER BY time ASC;", fromname, toname, toname, fromname); // 按时间升序
    char **result = GetTableInfo(s, sql, &row, &colnm);
    char ret[ContentSize] = {0};
    int i = 3;
    while (i < ((row + 1) * colnm))
    {
        strcat(ret, result[i++]);
        strcat(ret, ",");
    }
    strcat(ret, "\0");
    FreeTableInfo(result);
    return strdup(ret);
}

bool IsGroupExist(const char *toname)
{
    char sql[1024] = {0};
    sprintf(sql, "select count(*) from groupchat where groupname = '%s';", toname);
    char **result = GetTableInfo(s, sql, NULL, NULL);
    if (result == NULL)
    {
        return false;
    }
    int count = atoi(result[1]);
    FreeTableInfo(result);
    return count != 0;
}

bool AddGroup(const char *fromname, const char *toname)
{
    char sql[1024] = {0};
    sprintf(sql, "insert into groupchat (groupleader, groupname, member) values('%s','%s','%s');", fromname, toname, fromname);
    return SQLExec(s, sql);
}

bool IsGroupLeader(const char *toname, const char *fromname)
{
    char sql[1024] = {0};
    sprintf(sql, "select count(groupleader) from groupchat where (groupname = '%s' and groupleader = '%s');", toname, fromname);
    char **result = GetTableInfo(s, sql, NULL, NULL);
    if (result == NULL)
    {
        return false;
    }
    int count = atoi(result[1]);
    FreeTableInfo(result);
    return count != 0;
}

bool DeleteGroup(const char *toname)
{
    char sql[1024] = {0};
    sprintf(sql, "delete from groupchat where groupname = '%s';", toname);
    return SQLExec(s, sql);
}

bool JoinGroup(const char *toname, const char *fromname)
{
    char sql[1024] = {0};
    sprintf(sql, "insert into groupchat (groupname, member) values('%s','%s');", toname, fromname);
    return SQLExec(s, sql);
}

bool LeaveGroup(const char *toname, const char *fromname)
{
    char sql[1024] = {0};
    sprintf(sql, "delete from groupchat where (groupname = '%s' and member = '%s');", toname, fromname);
    return SQLExec(s, sql);
}

bool DisbandGroup(const char *toname)
{
    char sql[1024] = {0};
    sprintf(sql, "delete from groupchat where (groupname = '%s');", toname);
    return SQLExec(s, sql);
}

bool IsMember(const char *toname, const char *fromname)
{
    char sql[1024] = {0};
    sprintf(sql, "select count(*) from groupchat where (groupname = '%s' and member = '%s');", toname, fromname);
    char **result = GetTableInfo(s, sql, NULL, NULL);
    if (result == NULL)
    {
        return false;
    }
    int count = atoi(result[1]);
    FreeTableInfo(result);
    return count != 0;
}

char **GetGroupMember(const char *toname, int *size)
{
    char sql[1024] = {0};
    sprintf(sql, "select member from groupchat where groupname = '%s';", toname);
    char **result = GetTableInfo(s, sql, size, NULL);
    return result;
}

char *GetGroupHistory(const char *toname)
{
    char sql[1024] = {0};
    int row = 0;
    int colnm = 0;
    sprintf(sql, "SELECT fromname, time, content FROM chathistory where toname = '%s';", toname); // 按时间升序
    char **result = GetTableInfo(s, sql, &row, &colnm);
    char ret[ContentSize] = {0};
    int i = 3;
    while (i < ((row + 1) * colnm))
    {
        strcat(ret, result[i++]);
        strcat(ret, ",");
    }
    strcat(ret, "\0");
    FreeTableInfo(result);
    return strdup(ret);
}

char *FriendRequest(const char *fromname)
{
    char sql[1024] = {0};
    int row = 0;
    sprintf(sql, "SELECT fromname FROM friend where (toname = '%s') and (isok = 0);", fromname);
    char **result = GetTableInfo(s, sql, &row, NULL);
    char ret[ContentSize] = {0};
    int i = 1;
    while (i <= row)
    {
        strcat(ret, result[i++]);
        strcat(ret, ",");
    }
    strcat(ret, "\0");
    FreeTableInfo(result);
    return strdup(ret);
}

bool ViewFlag(const char *toname, const char *fromname, int flag)
{
    char sql[1024] = {0};
    sprintf(sql, "UPDATE friend SET isok = %d WHERE (fromname = '%s' and toname = '%s');", flag, fromname, toname);
    return SQLExec(s, sql);
}

char *GetFriend(const char *fromname)
{
    char sql[1024] = {0};
    int row = 0;
    sprintf(sql, "select toname from friend where fromname = '%s' and isok = 1;", fromname);
    char **result = GetTableInfo(s, sql, &row, NULL);
    char ret[ContentSize] = {0};
    if (row < 1)
    {
        strcpy(ret, "没有好友\0");
        printf("ret:%s", ret);
        return strdup(ret);
    }
    int i = 1;
    while (i <= row)
    {
        strcat(ret, result[i++]);
        strcat(ret, ",");
    }
    strcat(ret, "\0");
    FreeTableInfo(result);
    return strdup(ret);
}
